/*
 * Copyright 2007 Agile Plugins Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.agileplugins.monkey;

import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPackage;
import com.intellij.refactoring.PackageWrapper;
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

public class CreateComponentHandler implements Runnable {
    private Project project;
    private PsiDirectory psidirectory;
    private Properties properties;
    private PsiDirectory componentDirectory;
    private PsiDirectory testDirectory;

    public CreateComponentHandler(Project project, PsiDirectory baseDirectory, Properties properties) {
        this.psidirectory = baseDirectory;
        this.project = project;
        this.properties = properties;
    }

    public void run() {
        ProjectRootManager rootManager = ProjectRootManager
                .getInstance(project);
        ProjectFileIndex fileIndex = rootManager.getFileIndex();

        Module moduleForFile = fileIndex.getModuleForFile(psidirectory.getVirtualFile());
        boolean testSource = fileIndex.isInTestSourceContent(psidirectory.getVirtualFile());

        setUpTestAndSourceDirectories(fileIndex, moduleForFile, testSource);

        FileTemplateManager templateManager = FileTemplateManager.getInstance();
        templateManager.addRecentName("Component");

        String interfaceName = (String) properties.get("INTERFACE_NAME");
        String componentBase = (String) properties.get("TEMPLATE_TYPE");
        boolean data = componentBase.equals("Data");

        FileTemplate componentTemplate = templateManager.getTemplate(componentBase);
        FileTemplate componentUnitTestTemplate = templateManager.getTemplate(componentBase + "UnitTest");
        FileTemplate componentInterfaceTemplate = templateManager.getTemplate(componentBase + "Interface");

        PsiElement[] createdElements = new PsiElement[1];

        try {

            if (!data) {
                VirtualFile child = psidirectory.getVirtualFile().findChild(interfaceName + "." + StdFileTypes.JAVA.getDefaultExtension());
                if (child == null) {
                    if (componentInterfaceTemplate != null) {
                        FileTemplateUtil.createFromTemplate(createdElements, componentInterfaceTemplate,
                                null, properties, project, componentDirectory);
                        if (createdElements[0] != null) {
                            openFileContainingElement(createdElements[0]);
                        }
                    } else {
                        PsiClass anInterface = componentDirectory.createInterface(interfaceName);
                        if (anInterface != null) {
                            openFileContainingElement(anInterface);
                        }
                    }
                }
            }
            System.out.println("properties = " + properties);
            FileTemplateUtil.createFromTemplate(createdElements, componentTemplate,
                    null, properties, project, componentDirectory);
            if (createdElements[0] != null) {
                openFileContainingElement(createdElements[0]);
            }
            FileTemplateUtil.createFromTemplate(createdElements, componentUnitTestTemplate,
                    null, properties, project, testDirectory);
        }
        catch (Exception exception) {
            exception.printStackTrace();
            Messages.showMessageDialog(project, exception.getMessage(), "Cannot Create Component",
                    Messages.getErrorIcon());
        }
        PsiElement unitTest = createdElements[0];

        if (unitTest != null) {
            openFileContainingElement(unitTest);
        }
    }

    private void openFileContainingElement(PsiElement createdElement) {
//        ideview.selectElement(createdElement);
        VirtualFile virtualFile = createdElement.getContainingFile().getVirtualFile();
        FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
        fileEditorManager.openFile(virtualFile, true);
    }

    private void setUpTestAndSourceDirectories(ProjectFileIndex fileIndex, Module moduleForFile, boolean testSource) {
        componentDirectory = psidirectory;
        testDirectory = psidirectory;

        PsiPackage pck = psidirectory.getPackage();
        if (pck == null) {
            return;
        }
        PsiDirectory[] dirs = pck.getDirectories();
        for (int i = 0; i < dirs.length; i++) {
            PsiDirectory directory = dirs[i];
            VirtualFile virtualFile = directory.getVirtualFile();
            if (fileIndex.getModuleForFile(virtualFile) == moduleForFile) {
                boolean isTest = fileIndex.isInTestSourceContent(virtualFile);
                if (isTest != testSource) {
                    if (testSource) {
                        componentDirectory = directory;
                    } else {
                        testDirectory = directory;
                    }
                }
            }
            ;
        }
        if (componentDirectory == testDirectory) {
            PackageWrapper packagewrapper = new PackageWrapper(pck);

            VirtualFile[] sourceRoots = ModuleRootManager.getInstance(moduleForFile).getSourceRoots();
            List list = new ArrayList();
            for (int i = 0; i < sourceRoots.length; i++) {
                boolean testSourceDir = fileIndex.isInTestSourceContent(sourceRoots[i]);
                if (testSource != testSourceDir) {
                    list.add(sourceRoots[i]);
                }
            }
            if (list.size() == 0) {
                return;
            }
            VirtualFile virtualFile = null;
            if (list.size() == 1) {
                virtualFile = (VirtualFile) list.get(0);
            } else {
                for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                    VirtualFile file = (VirtualFile) iterator.next();
                    if (file.getName().equals("java")) {
                        virtualFile = file;
                        break;
                    }
                }
                if (virtualFile == null) {
                    VirtualFile[] objects = (VirtualFile[]) list.toArray(new VirtualFile[list.size()]);
                    virtualFile = MoveClassesOrPackagesUtil.chooseSourceRoot(packagewrapper, objects, testDirectory);
                }
            }
            System.out.println("virtualfile = " + virtualFile);
            if (virtualFile == null) {
                return;
            }
            try {
                PsiDirectory packageDirectoryInSourceRoot = RefactoringUtil.createPackageDirectoryInSourceRoot(packagewrapper, virtualFile);
                System.out.println("packageDirectoryInSourceRoot = " + packageDirectoryInSourceRoot);

                if (testSource) {
                    componentDirectory = packageDirectoryInSourceRoot;
                } else {
                    testDirectory = packageDirectoryInSourceRoot;
                }
            } catch (IncorrectOperationException e) {
                throw new RuntimeException(e);
            }

        }
    }
}
